#ifndef DATALINKEDLIST_H_
#define DATALINKEDLIST_H_

#include "Data.h"
#include <iostream>
using namespace std;

class DataLinkedList: public Data { // TODO previously was not derived from Data

protected:
	class Node {
	protected:
		/***************************************************************************************
		 * function name: Node(const Node& nodeToCopy)
		 * The Input: Node to be copied
		 * The output: None
		 * The Function operation: Empty implementation since node should not be copied
		***************************************************************************************/
		Node(const Node& nodeToCopy) {}

	public:
		Data* m_data; // pointer to data held in node
		Node* m_prevListNode; // pointer to previous node on list
		Node* m_nextListNode; // pointer to next node on list

		/***************************************************************************************
		 * function name: Node (Node* data)
		 * The Input: Pointer to data object to be set as node's data attribute
		 * The output: None
		 * The Function operation: Creates a new node pointing to given data object
		 ***************************************************************************************/
		Node(Data* data);

		/****************************************************************************************
		 * function name: virtual ~Node()
		 * The Input: None
		 * The output: None
		 * The Function operation: Destructs node object
		 ***************************************************************************************/
		virtual ~Node();

		void operator=(Data* newData) {m_data = newData;}

	}; // end ListNode class

	Node* m_headDummy; // pointer to first node on list
	Node* m_tailDummy; // pointer to last node on list

	/***************************************************************************************
	 * function name: DataLinkedList(const DataLinkedList& listToCopy)
	 * The Input: List to be copied
	 * The output: None
	 * The Function operation: Empty implementation since lists are not copied
	 ***************************************************************************************/
	DataLinkedList(const DataLinkedList& listToCopy) {}

public:
	class Iterator {
	protected:
		// TODO ADD COMMENTS
		Node* m_currNode; // pointer to current node on list, user can change the node it is pointing at and get a pointer to current data
		Node& getNodeRef() const;

	public:
		/***************************************************************************************
		 * function name: Iterator()
		 * The Input: None
		 * The output: None
		 * The Function operation: Creates a new iterator for data linked list
		 ***************************************************************************************/
		Iterator();

		/***************************************************************************************
		 * function name: Iterator(const Iterator& itrToCopy)
		 * The Input: Iterator to be copied
		 * The output: None
		 * The Function operation: Creates a new iterator pointing at same current node in
		 * 						   given iterator's list
		 ***************************************************************************************/
		Iterator(const Iterator& itrToCopy);

		/***************************************************************************************
		 * function name: virtual ~Iterator()
		 * The Input: None
		 * The output: None
		 * The Function operation: Destructs Iterator object
		 ***************************************************************************************/
		virtual ~Iterator();


		Iterator& operator ++();
		Iterator& operator --();

		/***************************************************************************************
		 * function name: Data& operator*() const
		 * The Input: None
		 * The output: Reference to data object of node being pointed by current node pointer
		 * The Function operation: Returns data attribute of node being pointed by
		 * 						   current node pointer. Method does not change the object
		 ***************************************************************************************/
		virtual Data* operator*() const {return m_currNode->m_data;}

		bool operator==(const Iterator& otherIterator) const;

		void operator=(Node& nodeToPoint) {m_currNode = &nodeToPoint;} // TODO CHECK IF BEST POSITION

		/***************************************************************************************
		 * function name: void addNode(Data& newData)
		 * The Input: Reference to data object to be added
		 * The output: None
		 * The Function operation: Adds given data object to the list
		 ***************************************************************************************/
		//virtual void addNode(Data& newData);

		friend class DataLinkedList; // TODO check if best solution
	}; // end Iterator class

public:

	void internalAdd(Data& newData, const Iterator& positionHolder);
	void removeNode(const Iterator& nodeHolder);
	void swapNodes(const Iterator& firstNodeHolder, const Iterator& secondNodeHolder);

	/***************************************************************************************
	 * function name: DataLinkedList()
	 * The Input: None
	 * The output: None
	 * The Function operation: Creates a new linked list holding Data objects
	 ***************************************************************************************/
	DataLinkedList();

	/***************************************************************************************
	 * function name: virtual ~DataLinkedList()
	 * The Input: None
	 * The output: None
	 * The Function operation: Destructs linked list object
	 ***************************************************************************************/
	virtual ~DataLinkedList() = 0;

	Iterator begin() const;
	Iterator end() const;

	bool isEmpty() const;
};

#endif
